<template>
    <span ref="numberElement">{{ formattedCurrentValue }}</span>
  </template>
  
  <script>
  export default {
    name: 'AnimateNumberInView',
    props: {
      from: {
        type: Number,
        required: true,
        default: 0
      },
      to: {
        type: [Number, String],
        required: true
      },
      duration: {
        type: Number,
        required: true,
        default: 2000 // 默认2秒
      }
    },
    data() {
      return {
        currentValue: this.from,
        targetValue: parseFloat(this.to),
        isAnimating: false, // 标记是否正在动画
        observer: null,     // 存储 IntersectionObserver 实例
      };
    },
    computed: {
      decimalPlaces() {
        // 获取目标值的小数位数
        const parts = this.to.toString().split('.');
        return parts.length > 1 ? parts[1].length : 0;
      },
      formattedCurrentValue() {
        // 格式化当前值，根据需要保留小数位数
        if (this.decimalPlaces > 0) {
          return parseFloat(this.currentValue).toFixed(this.decimalPlaces);
        } else {
          return Math.round(parseFloat(this.currentValue));
        }
      }
    },
    mounted() {
      this.initIntersectionObserver();
    },
    beforeDestroy() {
      if (this.observer) {
        this.observer.disconnect();
      }
    },
    methods: {
      initIntersectionObserver() {
        const options = {
          root: null, // 使用视口作为根元素
          rootMargin: '0px',
          threshold: 0.1, // 当元素10%进入视口时触发
        };
  
        this.observer = new IntersectionObserver((entries, observer) => {
          entries.forEach(entry => {
            if (entry.isIntersecting && !this.isAnimating) {
              console.log('元素进入视口，开始计数');
              this.animate();
            } else if (!entry.isIntersecting) {
              this.resetAnimation(); // 元素离开视口时重置状态
            }
          });
        }, options);
  
        // 开始观察目标元素
        this.observer.observe(this.$refs.numberElement);
      },
      animate() {
        this.isAnimating = true;
        const start = parseFloat(this.currentValue); // 确保起始值是数字
        const end = this.targetValue;
        const startTime = performance.now();
  
        const step = (currentTime) => {
          const elapsed = currentTime - startTime;
          const progress = Math.min(elapsed / this.duration, 1);
          this.currentValue = start + (end - start) * progress;
  
          if (progress < 1) {
            requestAnimationFrame(step);
          } else {
            // 确保最终值准确无误
            this.currentValue = end;
            this.isAnimating = false; // 动画完成后允许重新计数
          }
        };
  
        requestAnimationFrame(step);
      },
      resetAnimation() {
        this.currentValue = this.from; // 重置当前值为起始值
        this.isAnimating = false; // 重置动画标记
      }
    },
    watch: {
      // 监听从父组件传来的 `from` 和 `to` 属性的变化
      from(newVal) {
        this.currentValue = newVal;
      },
      to(newVal) {
        this.targetValue = parseFloat(newVal);
      }
    }
  };
  </script>
  
  <style scoped>
  /* 可以添加样式 */
  </style>